﻿#include "EasyTcpServer.h"



EasyTcpServer::EasyTcpServer()
{
    _sock = INVALID_SOCKET;
}

EasyTcpServer::~EasyTcpServer()
{
    this->close();
}

int EasyTcpServer::loadSocket()
{
#if defined(_WIN32)
    WORD wVer = MAKEWORD(2, 2);
    WSADATA data;
    WSAStartup(wVer, &data);
#endif
    return 0;
}

void EasyTcpServer::unloadSocket()
{
#if defined(_WIN32)
    WSACleanup();
#endif
}

SOCKET EasyTcpServer::initSocket()
{
    int retval = -1;
    do
    {
        if (INVALID_SOCKET == _sock)
            this->close();

        myprintf("正在创建 socket ...");
        _sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (INVALID_SOCKET == _sock) {
            myprintf("socket函数调用失败");
            break;
        }
        retval = 0;
    } while (false);
    return _sock;
}

bool EasyTcpServer::isRunning()
{
    bool suc = (INVALID_SOCKET != _sock);
    return suc;
}

void EasyTcpServer::closeSocket(SOCKET s)
{
    if (INVALID_SOCKET != s)
    {
#if 0
        shutdown(s, SD_RECEIVE);
        shutdown(s, SD_SEND);
#else
        shutdown(s, SD_BOTH);
#endif

#ifdef _WIN32
        closesocket(s);
#else
        close(s);
#endif
    }
}

void EasyTcpServer::closeClients()
{
    for (int i = 0; i < (int)_clients.size(); i++)
    {
        _clients[i]->closeClient();
        auto ptr = _clients[i];
        if (NULL != ptr)
            delete ptr;
    }
    _clients.clear();
}
void EasyTcpServer::closeSelf()
{
    closeSocket(_sock);
    _sock = INVALID_SOCKET;
}


void EasyTcpServer::close() {

    closeClients();
    closeSelf();
}

int EasyTcpServer::bind(const char* ip, unsigned short port)
{
    int retval = 0;

    do
    {
        myprintf("正在绑定 ( ip = %s,  port = %d)", ip ? ip : "INADDR_ANY", port);
        sockaddr_in _sin;
        _sin.sin_family = AF_INET;
        _sin.sin_port = htons(port);
        if (ip)
            _sin.sin_addr.s_addr = INADDR_ANY;
        else
            _sin.sin_addr.s_addr = inet_addr(ip);

        retval = ::bind(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
        if (SOCKET_ERROR == retval) {
            myprintf("bind 失败");
            break;
        }

    } while (false);
    return retval;
}

int EasyTcpServer::listen(int backlog)
{
    myprintf("监听...");
    int nret = ::listen(_sock, backlog); //SOMAXCONN,  SOMAXCONN_HINT(  number )
    if (SOCKET_ERROR == nret) {
        myprintf("listen 失败");
    }
    return nret;
}

int EasyTcpServer::onRun()
{
    int nret = -1;
    sockaddr_in clientSocket;
#ifdef  _WIN32
    int addrLen = 0;
#else
    size_t addrLen = 0;
#endif //  _WIN32

    do
    {
        if (!isRunning())
            break;

        SOCKET cSock = INVALID_SOCKET;
        fd_set fdRead;
        fd_set fdWrite;
        fd_set fdException;
        struct timeval tv = { 0, 55 };

        FD_ZERO(&fdRead);
        FD_ZERO(&fdWrite);
        FD_ZERO(&fdException);

        FD_SET(_sock, &fdRead);
        FD_SET(_sock, &fdWrite);
        FD_SET(_sock, &fdException);

        SOCKET maxSocket = _sock;
        for (int i = (int)_clients.size() - 1; i >= 0; i--) {
            FD_SET(_clients[i]->socketfd(), &fdRead);
            if (maxSocket < _clients[i]->socketfd())
                maxSocket = _clients[i]->socketfd();
        }

        nret = select((int)(maxSocket + 1), &fdRead, &fdWrite, &fdException, &tv);
        if (SOCKET_ERROR == nret) {
            myprintf("select 失败.");
            break;
        }
        if (FD_ISSET(_sock, &fdRead)) {
            FD_CLR(_sock, &fdRead);

            addrLen = (int)sizeof(sockaddr_in);
            cSock = accept(_sock, (sockaddr*)&clientSocket, &addrLen);
            if (INVALID_SOCKET == cSock) {
                myprintf("accept 失败.");
                break;
            }

            ClientSocket *pCSock = new ClientSocket(cSock, SOCKET_CLIENT_BUFFER_SIZE);
            if (pCSock) {
                // inet_ntoa 这个函数应该是使用了静态变量
                pCSock->_ip = inet_ntoa(clientSocket.sin_addr);
                pCSock->port = ntohs(clientSocket.sin_port);
                myprintf("已接受客户端( %s:%d )的连接. socket=%d.", pCSock->_ip.c_str(), pCSock->port, (int)pCSock->socketfd());

                // 这里可以通过给 g_clients 里的其他客户端发送一些消息，后再 push_back
                _clients.push_back(pCSock);
            }
            else {
                myprintf("内存分配失败， 关闭客户端 socket = %d.", cSock);
                closeSocket(cSock);
            }
        }

        // 
        for (int i = (int)_clients.size() - 1; i >= 0; i--) {
            SOCKET __sock = _clients[i]->socketfd();
            if (FD_ISSET(__sock, &fdRead)) {
                nret = ReceiveData(_clients[i]);
                if (nret < 0) {
                    auto iter = _clients.begin() + i;
                    if (iter != _clients.end()) {
                        (*iter)->closeClient();
                        _clients.erase(iter);
                    }
                }
            }
        }

        //for (int i = 0; i < (int)fdRead.fd_count; i++)
        //{
        //    nret = ReceiveData(fdRead.fd_array[i]);
        //    if (nret < 0) {
        //        auto iter = find(g_clients.begin(), g_clients.end(), fdRead.fd_array[i]);
        //        if (iter != g_clients.end()) {
        //            closesocket(*iter);
        //            g_clients.erase(iter);
        //        }
        //    }
        //}
        nret = 0;
    } while (false);

    return nret;
}

// -1 客户端退出, -2 发生异常
int EasyTcpServer::ReceiveData(ClientSocket* pClient)
{
    int nret = 0;
    char _recvBuff[4096];
    SOCKET cSock = INVALID_SOCKET;

    static long long calledCount = 0;
    calledCount++;
    myprintf("已被调用 %lld 次", calledCount);

    do
    {
        if (!pClient) {
            nret = -1;
            break;
        }

        cSock = pClient->socketfd();
        nret = ::recv(cSock, _recvBuff, sizeof(_recvBuff), 0);
        if (SOCKET_ERROR == nret) {
            myprintf("recv(_cSock ) 失败.");
            nret = -2;
            break;
        }
        else if (0 == nret) {

            // 并不能仅依赖这个返回值来判断断开，需要综合考量，需要查网络资料： socket 判断 断开
            myprintf("客户端 socket 已关闭(gracefully closed).");
            //closesocket(_cSock);
            //_cSock = INVALID_SOCKET;
            nret = -1;
            continue;
        }

        myprintf("本次收到来自客户端(<socket=%d>, [ ip=%s, port=%d ]) 的 %d 字节数据.", cSock, pClient->_ip.c_str(), pClient->port, nret);
        
        char *msgBuf = pClient->getBuffer();
        int lastPos = pClient->getLastPos();

        // 将收到的数据拷贝到消息缓冲区
        memcpy(&msgBuf[lastPos], _recvBuff, nret);
        lastPos += nret;
        pClient->setLastPos(lastPos);
        while (lastPos >= sizeof(DataHead)) {

            DataHead *head = (DataHead *)msgBuf;
            MessageBuildHelper *pMbh = pClient->getMessageBuildHelper();
            int msgLen = pMbh->getMessageLength(head);
            if (lastPos < msgLen)
                break;

            // 消息缓冲区剩余未处理数据的长度
            int nSize = lastPos - msgLen;

            // 处理网络消息
            onNetMsg(pClient, head, msgLen);

            // 未处理数据前移
            memcpy(msgBuf, msgBuf + msgLen, nSize);

            lastPos = nSize;
            pClient->setLastPos(lastPos);
        }

        nret = 0;
    } while (false);

    return nret;
}

int EasyTcpServer::onNetMsg(SOCKET _cSock, char* data, int dataLen)
{
    int nret = 0;
    myprintf("接收到的命令：[ %s ].", data);

    do
    {
        if (0 == stricmp(data, "exit")) {
            myprintf("客户端已退出.");
            //closesocket(_cSock);
            //_cSock = INVALID_SOCKET;
            nret = -1;
            continue;
        }
        else if (0 == stricmp(data, "getName")) {
            char msgBuf[] = "小强哦";
            nret = sendData(_cSock, msgBuf, sizeof(msgBuf));
        }
        else {
            char msgBuf[] = "???.我是服务器.";
            nret = sendData(_cSock, msgBuf, sizeof(msgBuf));
        }

    } while (0);
    return nret;
}

//int EasyTcpServer::onNetMsg(SOCKET _cSock, DataHead* data)
//{
//    int nret = 0;
//
//
//    return 0;
//}

int EasyTcpServer::onNetMsg(ClientSocket* pClient, DataHead* head, int bufLen)
{
    static long long calledCount = 0;
    calledCount++;
    myprintf("已被调用 %lld 次", calledCount);

    int ret = 0;
    MessageBuildHelper *pMbh = pClient->getMessageBuildHelper();
    MessageType type = pMbh->getMessageType(head);

    myprintf("正在处理来自客户端(<socket=%d>, [ ip=%s, port=%d ]) 的 [%d] 类型消息，长度 %d 字节数据.", pClient->socketfd(), pClient->_ip.c_str(), pClient->port, type, bufLen);

    switch (type)
    {
    case MessageType::MessageType_TextMessage: {
        //TextMessage* txtMsg = (TextMessage*)head;
        CTextMessage txtMsg;
        txtMsg.parse((DataHead*)head);
        const char* content = txtMsg.getString();
        //myprintf("客户端(<socket=%d>, [ ip=%s, port=%d ]) 发来文本消息：%s", pClient->socketfd(), pClient->_ip.c_str(), pClient->port, content);
    }
        break;
    default: 
        myprintf("来自客户端(<socket=%d>, [ ip=%s, port=%d ]) 的未知的 [%d] 类型消息.", pClient->socketfd(), pClient->_ip.c_str(), pClient->port, type);
        break;
    }

    return ret;
}

int EasyTcpServer::sendData(SOCKET _cSock, char* data, int dataLen)
{
    int nret = ::send(_cSock, data, dataLen, 0);
    return nret;
}
